"use strict";

(function() {
	/*
	 * var modes = [ { "freeHand": } ];
	 */
	var log = function(msg) {
		Firebug && Firebug.Console.log(msg);
	};
	
	alx.lj.LinkJuggernaut = function(document) {
		var me = this;
		
		var canvas = null, 
				prefs = null, 
				capturing = false, 
				linkList = [], 
				startPos = null, selectionMode = null, docUserSelect = null, userSelect = null, treeStyleTabDetected = null;
		
		var init = function() {
			prefs = alx.lj.prefs;
			treeStyleTabDetected = ("TreeStyleTabService" in window);
			
			// initCanvas();
			
			// document.body.addEventListener("DOMNodeInserted",
			// eventListeners.domNodeInserted, false);
			document.body.addEventListener("load", function () { alert("LOADED"); }, false);
			// eventListeners.domNodeRemoved, false);
			document.addEventListener("mousedown", eventListeners.handleMouseDown, true);
		};
		
		// Mouse related
		// ---------------------------------------------------------------------------------------------------
		// //
		var eventListeners = {
			handleMouseDown : function(e) {
				var pos;
				
				capturing = false;
				if (!isMouseDownTrigger(e))
					return;
				
				pos = getAbsolutePos(e);
				startPos = pos;
				
				attachEvents();
				
				e.preventDefault();
			},
			
			handleMouseMove : function(e) {
				if (!capturing && !isMouseMoveTrigger(e))
					return;
				
				var pos, hit;
				pos = getAbsolutePos(e);
				
				if (!capturing) {
					initCanvas();
					refreshLinkList();
					initSelectionMode();
					saveUserSelect();
					
					if (selectionMode) {
						selectionMode.setSelectables(linkList);
						selectionMode.selectionStart(startPos);
						
						capturing = true;
					}
				}
				
				capturing && selectionMode.handlePosition(pos);
			},
			
			handleMouseUp : function(e) {
				detachEvents();
				
				try {
					e.preventDefault();
					restoreUserSelect();
					
					if (capturing) {
						capturing = false;
						canvas.detach();
						
						selectionMode.selectionStop();
						handleHits(selectionMode.getHits());
					}
				} finally {
					canvas && canvas.detach();
				}
			},
			
			handleKeyDown : function(e) {
				switch (e.keyCode) {
					case prefs.keys.cancelSelection():
						userActions.cancelSelection();
						break;
				}
			},
			
			handleKeyUp : function(e) {
				
			},
			
			domNodeInserted : function(e) {
				// log(e.target.tagName);
				
				// if (e.target.tagName == "A")
				// validateAndInsertLink(e.target);
			},
			
			domNodeRemoved : function(e) {
				// log(e);
			}
		};
		
		var isMouseMoveTrigger = function(e) {
			if (!startPos)
				return false;
			
			var pos = getAbsolutePos(e);
			var dragOk = (calcDistance(startPos, pos) >= prefs.trigger.minPixelDrag());
			
			return (dragOk);
		};
		
		var isMouseDownTrigger = function(mouseEventArgs) {
			var button = prefs.trigger.mouseButton();
			var ctrl = prefs.trigger.ctrlRequired();
			var alt = prefs.trigger.altRequired();
			var shift = prefs.trigger.shiftRequired();
			
			var mouseOk = ((mouseEventArgs.button === button) && (mouseEventArgs.ctrlKey === ctrl) && (mouseEventArgs.altKey === alt) && (mouseEventArgs.shiftKey === shift));
			
			var targetOk = true;// (mouseEventArgs.target &&
													// mouseEventArgs.target.tagName.toLowerCase() !==
													// "a");
			
			return (mouseOk && targetOk);
		};
		// ----------------------------------------------------------------------------------------------------------------
		// //
		
		var userActions = {
			cancelSelection : function() {
				var mouseUp = function(e) {
					e.preventDefault();
					document.removeEventListener("mouseup", mouseUp, true);
				};
				
				detachEvents();
				document.addEventListener("mouseup", mouseUp, true);
				
				capturing = false;
				selectionMode && selectionMode.selectionStop();
				
				canvas.detach();
			}
		};
		
		var detachEvents = function() {
			document.removeEventListener("mouseup", eventListeners.handleMouseUp, true);
			document.removeEventListener("mousemove", eventListeners.handleMouseMove, true);
			document.removeEventListener("keydown", eventListeners.handleKeyDown, true);
			document.removeEventListener("keyup", eventListeners.handleKeyUp, true);
		};
		
		var attachEvents = function() {
			document.addEventListener("mouseup", eventListeners.handleMouseUp, true);
			document.addEventListener("mousemove", eventListeners.handleMouseMove, true);
			document.addEventListener("keydown", eventListeners.handleKeyDown, true);
			document.addEventListener("keyup", eventListeners.handleKeyUp, true);
		};
		
		var initSelectionMode = function(x, y) {
			var sm = null, args = null, modes = alx.lj.selectionModes;
			
			for ( var key in modes) {
				if (modes.hasOwnProperty(key)) {
					if (key.toLowerCase() === prefs.general.selectionMode().toLowerCase()) {
						sm = modes[key];
						
						if (selectionMode && (selectionMode instanceof sm)) return;
						
						selectionMode = new sm({ canvas : canvas });
						return;
					}
				}
			}
			
			return null;
		};
		
		var validateAndInsertLink = function(linkElem) {
		
			if (isLinkValid(linkElem) && isFilterApproved(linkElem)) {
				args = {
					elem : linkElem,
					canvas : canvas,
					doc : document
				};
				
				linkList.push(new alx.lj.Link(args));
			}
		};
		
		var rebuildLinkList = function() {
			linkList = [];
			refreshLinkList();
		};
		
		var refreshLinkList = function () {
			var id,
					args, 
					link,
					fromScratch, 
					startingSize,
					linkCollection,
					lcLength,
					linkElement;
			
			
			id = null;
			startingSize = linkList.length;
			linkCollection = document.getElementsByTagName("a");
			lcLength = linkCollection.length;
			
			for (var i=0; i < lcLength; i++) {
				linkElement = linkCollection[i];
				
				if (startingSize > 0) {
					id = linkElement.getAttribute("data-linkJuggernautId");
				}
				else {
					id = null;
				}
				
				if (id) {
					linkList[id].refreshBounds();
				} 
				else {
					if (isLinkValid(linkElement) && isFilterApproved(linkElement)) {
						args = {
							elem : linkElement,
							canvas : canvas
						};
						
						id = linkList.push(new alx.lj.Link(args)) - 1;
						linkElement.setAttribute("data-linkJuggernautId", id);
					}
				} 
			}
		};
		
		var isFilterApproved = function(linkElem) {
			
			//
			
			return true;
		};
		
		var isLinkValid = function(linkElem) {
			var elem, styles, href;
			
			if (!linkElem)
				return false;
			
			href = linkElem.href;
			styles = document.defaultView.getComputedStyle(linkElem);
			
			var hrefOk = (href && (href.substring(href.length-1, href.length) != "#"));
			var visualOk = (styles.display != "none") && (styles.visibility != "hidden") && (parseFloat(styles.opacity) > 0);
			
			return (hrefOk && visualOk);
		};
		
		/*
		 * var translatePosition = function(amountX, amountY) { if (!_poly) throw
		 * "Polyline is null";
		 * 
		 * var val = "translate(" + parseInt(amountX) + "," + parseInt(amountY) +
		 * ")"; _poly.setAttribute("transform", val); };
		 */

		var getAbsolutePos = function(e) {
			var pageX = e.clientX + document.defaultView.pageXOffset;
			var pageY = e.clientY + document.defaultView.pageYOffset;
			
			return {
				x : pageX,
				y : pageY
			};
		};
		
		var openInNewTab = function(links) {
			var linksLength;
			
			if (treeStyleTabDetected)
				TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab, true);
			
			try {
				linksLength = links.length;
				for (var i=0; i < linksLength; i++) {
					var link = links[i];
					
					gBrowser.addTab(link.getHref());
				}
			} finally {
				if (treeStyleTabDetected)
					TreeStyleTabService.stopToOpenChildTab(gBrowser.selectedTab);
			}
		};
		
		var handleHits = function(hits) {
			openInNewTab(hits);
		};
		
		var getCanvas = function() {
			return canvas;
		};
		
		var getDocumentHeight = function() {
			var D = document;
			
			return Math.max(Math.max(D.body.scrollHeight, D.documentElement.scrollHeight), Math.max(D.body.offsetHeight, D.documentElement.offsetHeight), Math.max(
					D.body.clientHeight, D.documentElement.clientHeight));
		};
		
		var initCanvas = function() {
			if (!canvas || canvas.disposed) {
				canvas = new alx.svg.Canvas(document);
			}
			
			canvas.clear();
			canvas.attach();
		};
		
		var calcDistance = function(p1, p2) {
			var dx = Math.abs(p1.x - p2.x);
			var dy = Math.abs(p1.y - p2.y);
			
			return Math.sqrt(dx * dx + dy * dy);
		};
		
		var saveUserSelect = function() {
			docUserSelect = document.body.style.MozUserSelect = "none";
		};
		
		var restoreUserSelect = function() {
			document.body.style.MozUserSelect = docUserSelect;
		};
		
		/* ----------- */
		init();
	};
})();